<!-- 创建商品 -->
<template>
  <div>
    <!-- 商品（Spu）介绍 -->
    <el-card>
      <h4 style="margin-bottom: 10px">商品（Spu）介绍</h4>
      <el-form
        label-width="150px"
        ref="formRef"
        :rules="rulesA"
        :model="submitData"
        status-icon
      >
        <el-form-item prop="title" label="商品名称">
          <el-input v-model="submitData.title" />
        </el-form-item>
        <el-form-item label="原始价格" prop="originalPrice">
          <el-input
            v-model="submitData.originalPrice"
            oninput="value=value.replace(/[^\d.\d]/g,'')"
          >
            <template #append>元</template>
          </el-input>
        </el-form-item>
        <el-form-item label="当前价格" prop="price">
          <el-input
            v-model="submitData.price"
            oninput="value=value.replace(/[^\d.\d]/g,'')"
          >
            <template #append>元</template>
          </el-input>
        </el-form-item>
        <el-form-item label="VIP价格" prop="vipPrice">
          <el-input
            v-model="submitData.vipPrice"
            oninput="value=value.replace(/[^\d.\d]/g,'')"
          >
            <template #append>元</template>
          </el-input>
        </el-form-item>
        <el-form-item label="剩余库存">
          <el-input disabled v-model="submitData.stock" />
        </el-form-item>
        <el-form-item label="运费模板">
          <el-select
            v-model="submitData.freightTemplateId"
            clearable
            @focus="getFreight"
            placeholder="选择商品运费模板"
          >
            <el-option
              v-for="item in freightList"
              :key="item.id"
              :label="item.title"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="是否在售" prop="status">
          <el-radio-group v-model="submitData.status">
            <el-radio :label="1">在售</el-radio>
            <el-radio :label="0">下架</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="商品图片">
          <el-upload
            v-model:file-list="imgList"
            :headers="{ AdminToken: token }"
            :action="action"
            :on-success="handleSuccess"
            :on-remove="handleRemove"
            :limit="5"
            list-type="picture-card"
          >
            <el-icon>
              <Plus />
            </el-icon>
          </el-upload>
        </el-form-item>
        <el-form-item label="商品单位" prop="unit">
          <el-input v-model="submitData.unit" placeholder="件/个/盒" />
        </el-form-item>
        <el-form-item label="所属类目">
          <el-cascader
            clearable
            @focus="getCategory"
            v-model="submitData.categoryId"
            :props="props"
            placeholder="请选择类目"
            :options="categoryList"
            :show-all-levels="false"
          />
        </el-form-item>
        <el-form-item label="商品简介">
          <el-input v-model="submitData.description" />
        </el-form-item>
        <el-form-item label="商品详细介绍" prop="detail">
          <RichText v-model="submitData.detail"></RichText>
        </el-form-item>
      </el-form>
    </el-card>
    <!-- 商品参数 -->
    <el-card>
      <el-space direction="vertical" alignment="left">
        <h4>商品参数</h4>
        <el-button type="primary" plain @click="dialogA = true">添加</el-button>
      </el-space>
      <el-table :data="submitData.attributeList">
        <el-table-column label="商品参数名称" prop="attribute" align="center" />
        <el-table-column label="商品参数值" prop="value" align="center" />
        <el-table-column label="操作" align="center">
          <template #default="scope">
            <el-button type="danger" @click="deleParameter(scope.$index)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 商品参数弹窗 -->
      <el-dialog v-model="dialogA" title="设置商品参数" width="700px" destroy-on-close>
        <el-form
          ref="attrForm"
          :model="attrItem"
          :rules="rulesB"
          :label-width="150"
          status-icon
        >
          <el-form-item label="商品参数名称" prop="attribute">
            <el-input v-model.trim="attrItem.attribute" />
          </el-form-item>
          <el-form-item label="商品参数值" prop="value">
            <el-input v-model.trim="attrItem.value" />
          </el-form-item>
        </el-form>
        <template #footer>
          <span>
            <el-button @click="dialogA = false">取消</el-button>
            <el-button type="primary" @click="addParameter(attrForm)">确定</el-button>
          </span>
        </template>
      </el-dialog>
    </el-card>
    <!-- 规格维度 -->
    <el-card>
      <el-space direction="vertical" alignment="left">
        <h4>规格维度</h4>
        <el-button
          type="primary"
          plain
          @click="
            () => {
              parameterStatus = 0;
              dialogB = true;
            }
          "
          >添加</el-button
        >
      </el-space>
      <el-table :data="submitData.specificationList">
        <el-table-column label="维度id" align="center" />
        <el-table-column label="维度名称" prop="title" align="center" />
        <el-table-column label="创建时间" prop="gmtCreate" align="center">
          <template #default="scope">
            {{ new Date(scope.row.gmtCreate).computeDate() }}
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center">
          <template #default="scope">
            <el-button
              type="primary"
              @click="
                () => {
                  Object.assign(specification, scope.row);
                  parameterIndex = scope.$index;
                  parameterStatus = 1;
                  dialogB = true;
                }
              "
              >修改</el-button
            >
            <el-button type="danger" @click="delelSpecifica(scope.$index)"
              >删除</el-button
            >
          </template>
        </el-table-column>
      </el-table>
      <!-- 规格维度弹窗 -->
      <el-dialog
        v-model="dialogB"
        :title="parameterStatus ? '修改规格' : '创建规格'"
        width="700px"
        destroy-on-close
      >
        <el-form
          ref="specificaForm"
          :model="specification"
          :rules="rulesB"
          @submit.prevent
          :label-width="150"
          status-icon
        >
          <el-form-item label="类型名称" prop="title">
            <el-input
              v-model.trim="specification.title"
              @keyup.enter="setSpecifica(specificaForm)"
            />
          </el-form-item>
        </el-form>
        <template #footer>
          <span>
            <el-button @click="dialogB = false">取消</el-button>
            <el-button type="primary" @click="setSpecifica(specificaForm)"
              >{{ parameterStatus ? "修改" : "创建" }}规格</el-button
            >
          </span>
        </template>
      </el-dialog>
    </el-card>
    <!-- 商品（Sku）详情 -->
    <el-card>
      <template #header>
        <el-space direction="vertical" alignment="flex-start">
          <h4>商品（Sku）详情</h4>
          <el-button type="primary" plain @click="dialogC = true">批量定价</el-button>
          <el-space
            wrap
            alignment="flex-start"
            v-for="(item, index) in submitData.specificationList"
            :key="item.gmtCreate"
          >
            <el-tag type="warning">{{ item.title }}</el-tag>
            <el-tag
              v-for="tag in item.values"
              :key="tag"
              closable
              :disable-transitions="false"
              @close="handleClose(tag, index)"
            >
              {{ tag }}
            </el-tag>
            <el-input
              ref="InputRef"
              v-if="item.inputSkuTagVisible"
              v-model="item.inputSkuTagValue"
              @keyup.enter="handleInputConfirm(index)"
              @blur="handleInputConfirm(index)"
            />
            <el-tag effect="plain" v-else @click="showInput(index)"> + 添加 </el-tag>
          </el-space>
        </el-space>
      </template>
      <el-table border :data="submitData.skuList" :span-method="arrayRow">
        <el-table-column
          :label="item.title"
          :prop="'id_' + item.title"
          v-for="item in submitData.specificationList"
          :key="item.gmtCreate"
          align="center"
        >
        </el-table-column>
        <el-table-column label="SkuId" align="center" />
        <el-table-column label="￥价格(元)" align="center" :width="200">
          <template #default="scope" :width="200">
            <el-input-number :min="0" v-model="scope.row.price" :precision="2" />
          </template>
        </el-table-column>
        <el-table-column label="￥VIP价(元)" align="center" :width="200">
          <template #default="scope">
            <el-input-number :min="0" v-model="scope.row.vipPrice" :precision="2" />
          </template>
        </el-table-column>
        <el-table-column label="￥吊牌价(元)" align="center" :width="200">
          <template #default="scope">
            <el-input-number :min="0" v-model="scope.row.originalPrice" :precision="2" />
          </template>
        </el-table-column>
        <el-table-column label="库存(件)" align="center" :width="200">
          <template #default="scope">
            <el-input-number :min="0" v-model="scope.row.stock" />
          </template>
        </el-table-column>
        <el-table-column label="重量(克)" align="center" :width="200">
          <template #default="scope">
            <el-input-number :min="0" v-model="scope.row.weight" />
          </template>
        </el-table-column>
        <el-table-column label="SKU图片" align="center" :width="200">
          <template #default="scope">
            <el-upload
              :show-file-list="false"
              :headers="{ AdminToken: token }"
              :action="action"
              :on-success="handleAvatarSuccess"
            >
              <img v-if="scope.row.img" :src="scope.row.img" style="height: 30px" />
              <el-icon v-else :size="20">
                <Upload @click="imgrow = scope.row" />
              </el-icon>
            </el-upload>
          </template>
        </el-table-column>
        <el-table-column label="条形码" align="center" :width="200">
          <template #default="scope">
            <el-input v-model="scope.row.barCode" :readonly="true">
              <template #append>
                <el-button
                  type="info"
                  @click="
                    () => {
                      scope.row.barCode = new Date().getTime();
                    }
                  "
                  >随机</el-button
                >
              </template>
            </el-input>
          </template>
        </el-table-column>
      </el-table>
      <!-- 批量定价弹出框 -->
      <el-dialog
        v-model="dialogC"
        :title="parameterStatus ? '修改规格' : '创建规格'"
        width="500px"
        destroy-on-close
      >
        <el-form
          :rules="rulesC"
          label-position="left"
          :label-width="100"
          style="margin-left: 100px"
        >
          <el-form-item label="现价(￥)" prop="price">
            <el-input-number :min="0" v-model="price" :precision="2" :step="0.1" />
          </el-form-item>
          <el-form-item label="VIP价格(￥)" prop="vipPrice">
            <el-input-number :min="0" v-model="vipPrice" :precision="2" :step="0.1" />
          </el-form-item>
          <el-form-item label="吊牌价(￥)" prop="originalPrice">
            <el-input-number
              :min="0"
              v-model="originalPrice"
              :precision="2"
              :step="0.1"
            />
          </el-form-item>
        </el-form>
        <template #footer>
          <span>
            <el-button @click="dialogC = false">取消</el-button>
            <el-button type="primary" @click="alterAllPrice">确认</el-button>
          </span>
        </template>
      </el-dialog>
    </el-card>
    <div style="margin: 10px 0px; display: flex; justify-content: flex-end">
      <el-button type="info" @click="deleTag">关闭</el-button>
      <el-button type="primary" @click="submitList(formRef)">保存商品</el-button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { post } from "@/request/http";
import { ref, reactive, computed, watch, nextTick } from "vue";
import Cookie from "js-cookie";
import { type FormInstance, type UploadProps, ElMessage, ElMessageBox } from "element-plus";
import { GoodType } from "../../../types/index";
import router from "@/router";
import useInfoStore from "@/stores";
const { userTag } = useInfoStore();
// 跨行的类型
interface SpanMethodProps {
  rowIndex: number;
  columnIndex: number;
}

const token = Cookie.get("token");
const action = "/upload/admin";

// 节点ref
const attrForm = ref()
const specificaForm = ref()
const formRef = ref()
const InputRef = ref()

let dialogA = ref(false); //参数弹出框
let dialogB = ref(false); //规格维度弹窗
let parameterStatus = ref(0); //规格维度状态0为创建1为修改
let parameterIndex = ref(0); //规格维度修改的下标
let dialogC = ref(false); //批量定价的弹出框
// 在批量定价的弹出框中，用于定义全部的价格
let price = ref(0); //现价
let vipPrice = ref(0); //VIP价格
let originalPrice = ref(0); //吊牌价
let imgrow: any = reactive({}); //上传图片的行
let imgList: any = ref([]); //渲染在页面的图片路径
// 提交需要的数据
let submitData = reactive(new GoodType());
let attrItem: any = reactive({ attribute: "", value: "" }); //表单参数对象
let specification: any = reactive({
  //表单维度对象
  gmtCreate: "",
  title: "",
  gmtUpdate: "",
  inputSkuTagValue: "",
  inputSkuTagVisible: false,
  values: [],
});
let categoryList: any = ref([]); //类目选择的数据
let freightList: any = ref([]); //运费模板选择的数据
// 类目级联选择器的配置
const props = {
  label: "title",
  children: "childrenList",
  value: "id",
  emitPath: false,
};
let validatePrice = (rule: any, value: any, callback: any) => {
  if (price.value < vipPrice.value) {
    callback(new Error("现价不能小于VIP价"));
  } else if (price.value > originalPrice.value) {
    callback(new Error("现价不能大于吊牌价"));
  }
  callback();
};
let validateVipPrice = (rule: any, value: any, callback: any) => {
  if (price.value < vipPrice.value) {
    callback(new Error("ViP价不能大于现价"));
  }
  callback();
};
let validateOriginalPrice = (rule: any, value: any, callback: any) => {
  if (originalPrice.value < price.value) {
    callback(new Error("吊牌价不能小于现价"));
  }
  callback();
};
// 表单验证规则
const rulesA = {
  title: [{ required: true, message: "请输入商品名称", trigger: "blur" }],
  price: [{ required: true, message: "请输入当前价格", trigger: "blur" }],
  originalPrice: [{ required: true, message: "请输入原始价格", trigger: "blur" }],
  vipPrice: [{ required: true, message: "请输入VIP价格", trigger: "blur" }],
  status: [{ required: true }],
  unit: [{ required: true, message: "请输入商品单位", trigger: "blur" }],
  detail: [{ required: true, message: "请输入商品详细介绍", trigger: "blur" }],
};
const rulesB = {
  //弹出框的验证规则
  attribute: [{ required: true, message: "请输入商品参数名称", trigger: "blur" }],
  value: [{ required: true, message: "请输入参数值", trigger: "blur" }],
  title: [{ required: true, message: "请输入类型名称", trigger: "blur" }],
};

//价格的验证规则
const rulesC = {
  price: [{ trigger: "change", validator: validatePrice }],
  vipPrice: [{ trigger: "change", validator: validateVipPrice }],
  originalPrice: [{ trigger: "change", validator: validateOriginalPrice }],
};

// 跨行计算
const arrayRow = ({ rowIndex, columnIndex }: SpanMethodProps) => {
  let specList = submitData.specificationList.filter((i) => i.values.length > 0); //获取规格列表
  if (columnIndex < specList.length - 1) {
    //对要跨行的列进行计算(最后的属性列不计入)
    let rowSpanNum = 1; //跨行的数量
    for (let index = columnIndex + 1; index < specList.length; index++) {
      rowSpanNum *= specList[index].values.length; //累乘获取
    }
    if (rowIndex % rowSpanNum == 0) {
      return { rowspan: rowSpanNum, colspan: 1 };
    } else {
      return { rowspan: 0, colspan: 0 };
    }
  }
};
// 笛卡尔积算法
const cartesianProductOf = (list: any[]) => {
  return list.reduce(
    (total, next) => {
      var array: any[] = [];
      total.forEach((item: any) => {
        next.forEach((item2: any) => {
          array.push(item.concat([item2]));
        });
      });
      return array;
    },
    [[]]
  );
};
// 计算skuList
const getSkuList = (Val: any) => {
  let cloneNewVal = { ...Val.value }
  let attrName: any[] = []; //规格名数组
  let attrValue = []; //规格值数组
  for (let key in cloneNewVal) {
    if (cloneNewVal[key].length) {
      attrName.push(key);
      attrValue.push(cloneNewVal[key]);
    }
  }
  // 表格内容数据（笛卡尔积算法）
  let finalArr = cartesianProductOf(attrValue);
  if (finalArr.flat().length == 0) finalArr = []; //清空数组
  // 表格内容
  submitData.skuList = finalArr?.map((item: any) => {
    let line = submitData.skuList.find((v: any) => v.title == item.join(",")); //查找是否有对应数据
    let obj: any = {
      price: 0,
      vipPrice: 0,
      originalPrice: 0,
      stock: 0,
      barCode: "",
      weight: 0,
      img: "",
      title: item.join(","),
      specification: "",
    };
    obj = line ? Object.assign(obj, line) : obj;
    for (let i = 0; i < item.length; i++) {
      obj["id_" + attrName[i]] = item[i];
      obj.specification += attrName[i] + "_" + item[i] + ",";
    }
    return obj;
  });
};
// 请求类目列表
const getCategory = () => {
  if (categoryList.value.length) return; //在没有类目数据的时候请求
  post({ _gp: "admin.category", _mt: "categoryTree" }).then((res) => {
    if (200 == res?.errno) {
      //成功状态码
      categoryList.value = res.data;
    }
  });
};
// 请求运费模板
const getFreight = () => {
  if (freightList.value.length) return;
  post({ _gp: "admin.freight", _mt: "list" }).then((res) => {
    if (200 == res?.errno) {
      //成功状态码
      freightList.value = res.data;
    }
  });
};
// 添加参数
const addParameter = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.validate((valid) => {
    if (valid) {
      submitData.attributeList.push({ ...attrItem });
      ElMessage.success("设置成功");
      dialogA.value = false;
    }
  });
};
// 删除参数
const deleParameter = (index: number) => {
  ElMessageBox.confirm("是否删除本行参数?", "提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      submitData.attributeList.splice(index, 1);
      ElMessage.success("删除参数成功");
    })
    .catch(() => {
      ElMessage.info("删除取消");
    });
};
// 提交规格(添加和修改)
const setSpecifica = (formEl: FormInstance | undefined) => {
  if (!formEl) return;
  formEl.validate((valid) => {
    if (valid) {
      let nowDate = new Date().getTime(); //获取当前时间
      specification.gmtUpdate = nowDate;
      specification.gmtCreate = nowDate;
      if (0 == parameterStatus.value) {
        submitData.specificationList.push({ ...specification });
        ElMessage.success("创建规格成功");
        dialogB.value = false;
        return;
      }
      // 获取列表中对应的行，把表单中的数据克隆给该行
      Object.assign(
        submitData.specificationList[parameterIndex.value],
        specification
      );
      ElMessage.success("修改规格成功");
      dialogB.value = false;
    }
  })
}
// 删除规格
const delelSpecifica = (index: number) => {
  ElMessageBox.confirm("是否删除本行规格?", "提示", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      submitData.specificationList.splice(index, 1);
      ElMessage.success("删除规格成功");
    })
    .catch(() => {
      ElMessage.info("删除取消");
    });
};
// 显示添加规格值的输入框
const showInput = (index: number) => {
  submitData.specificationList[index].inputSkuTagVisible = true;
  nextTick(() => {
    (InputRef as any).value[0].input.focus()
  })
}
// 添加规格值tag
const handleInputConfirm = (index: number) => {
  let list = submitData.specificationList[index]
  //不为空
  if (list.inputSkuTagValue) {
    if (list.values.find((v: any) => list.inputSkuTagValue == v)) {
      ElMessage.info('含有相同tag')
    } else {
      list.values.push(list.inputSkuTagValue); //添加标签
      getSkuList(calculateAttribute); //计算表格
    }
  }
  list.inputSkuTagValue = ""; //清空输入框
  list.inputSkuTagVisible = false; //隐藏输入框
};
let calculateAttribute = computed(() => {
  // 初始化
  let obj: any = {};
  submitData.specificationList.forEach((item) => {
    //规格名:规格值     //'颜色':'尺寸'
    obj[item.title] = item.values;
  });
  return obj
});
// 关闭规格值tag
const handleClose = (tag: string, index: number) => {
  let { values } = submitData.specificationList[index];
  values.splice(values.indexOf(tag), 1);
  getSkuList(calculateAttribute); //计算表格
};

// 确认批量修改
const alterAllPrice = () => {
  submitData.skuList.forEach((item: any) =>
    Object.assign(item, { price: price.value, vipPrice: vipPrice.value, originalPrice: originalPrice.value })
  );
  dialogC.value = false; //关闭定价弹窗
};
// 表单图片上传成功
const handleSuccess: UploadProps["onSuccess"] = (response, uploadFile, uploadFiles) => {
  if (200 == response.errno) {
    submitData.imgList = uploadFiles.map((i: any) => i.response.url);
    submitData.img = submitData.imgList[0];
  }
};
//表单图片删除成功
const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
  submitData.imgList = uploadFiles.map((i: any) => i.response.url);
  submitData.img = submitData.imgList[0];
}
// 表格图片上传成功后
const handleAvatarSuccess: UploadProps["onSuccess"] = (response) => {
  if (200 == response?.errno) {
    imgrow.img = response.url; //获取图片路径
  }
}
// 提交表单
const submitList = (formEl: FormInstance | undefined) => {
  if (!formEl) return
  formEl.validate((valid) => {
    if (valid) {
      let spuDTO = JSON.stringify({ ...submitData });
      ElMessageBox.confirm("是否确认提交商品?", "提示", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          let obj = { _gp: "admin.product", _mt: "create", spuDTO };
          post(obj).then((res) => {
            if (200 == res?.errno) {
              ElMessage.success("添加商品成功");
              ElMessageBox.confirm("是否继续添加商品?", "提示", {
                confirmButtonText: "确认",
                cancelButtonText: "取消",
                type: "info",
              }).then(() => {
                Object.assign(submitData, new GoodType())//重置数据
                imgList.value = []
              }).catch(() => {
                deleTag(); //关闭当前页，跳转到商品列表
              })
            }
          });
        })
        .catch(() => {
          ElMessage.info("取消操作");
        });
    }
  })
}
// 关闭当前页
const deleTag = () => {
  router.replace({ name: 'list' })
  userTag.nameToClose('create')
}
watch(dialogA, (n) => {
  //监听参数弹出框
  if (!n) Object.assign(attrItem, { attribute: "", value: "" });
})
watch(dialogB, (n) => {
  //监听参数弹出框
  if (!n)
    Object.assign(specification, {
      gmtCreate: "",
      title: "",
      gmtUpdate: "",
      inputSkuTagValue: "",
      inputSkuTagVisible: false,
      values: [],
    });
})
watch(dialogC, (n) => {
  //监听定价弹出框
  if (!n) {
    price.value = 0;
    vipPrice.value = 0;
    originalPrice.value = 0
  }
})
// 监听规格数据
watch(calculateAttribute, (n) => {
  getSkuList(n)
})
</script>

<style></style>
